package com.yy.wga.mp.module.pay.manager;

import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.extra.servlet.ServletUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yy.wga.mp.module.pay.request.CreatePrePayOrderRequest;
import com.yy.wga.mp.module.pay.request.OauthTokenRequest;
import com.yy.wga.mp.module.pay.request.QueryUserInfoRequest;
import com.yy.wga.mp.module.pay.request.TransferRequest;
import com.yy.wga.mp.module.pay.response.CreatePrePayOrderResponse;
import com.yy.wga.mp.module.pay.response.OauthTokenResponse;
import com.yy.wga.mp.module.pay.response.QueryUserInfoResponse;
import com.yy.wga.mp.module.pay.response.TransferResponse;
import com.yy.wga.mp.module.pay.service.PayOrderService;
import com.yy.wga.mp.module.pay.service.PayTransferOrderService;
import com.yy.wga.mp.module.pay.client.request.alipay.AliPayAppPreOrderRequest;
import com.yy.wga.mp.module.pay.client.request.alipay.AliPayH5PreOrderRequest;
import com.yy.wga.mp.module.pay.client.request.alipay.AliPayOauthTokenRequest;
import com.yy.wga.mp.module.pay.client.request.alipay.AliPayQueryUserInfoRequest;
import com.yy.wga.mp.module.pay.client.request.alipay.AliPayRefundRequest;
import com.yy.wga.mp.module.pay.client.request.alipay.AliPayTransferRequest;
import com.yy.wga.mp.module.pay.client.request.wechat.WechatAppPreOrderRequest;
import com.yy.wga.mp.module.pay.client.request.wechat.WechatH5PreOrderRequest;
import com.yy.wga.mp.module.pay.client.request.wechat.WechatJsPreOrderRequest;
import com.yy.wga.mp.module.pay.client.request.wechat.WechatRefundRequest;
import com.yy.wga.mp.module.pay.client.request.wechat.WechatTransferRequest;
import com.yy.wga.mp.module.pay.client.response.alipay.AliPayAppPreOrderResponse;
import com.yy.wga.mp.module.pay.client.response.alipay.AliPayH5PreOrderResponse;
import com.yy.wga.mp.module.pay.client.response.alipay.AliPayOauthTokenResponse;
import com.yy.wga.mp.module.pay.client.response.alipay.AliPayQueryUserInfoResponse;
import com.yy.wga.mp.module.pay.client.response.alipay.AliPayTransferResponse;
import com.yy.wga.mp.module.pay.client.response.wechat.WechatAppPreOrderResponse;
import com.yy.wga.mp.module.pay.client.response.wechat.WechatH5PreOrderResponse;
import com.yy.wga.mp.module.pay.client.response.wechat.WechatJsPreOrderResponse;
import com.yy.wga.mp.module.pay.client.response.wechat.WechatRefundResponse;
import com.yy.wga.mp.module.pay.client.response.wechat.WechatTransferResponse;
import com.yy.wga.common.core.exception.BusinessException;
import com.yy.wga.mp.common.interceptor.RequestUserHolder;
import com.yy.wga.mp.common.utils.common.IdUtils;
import com.yy.wga.mp.common.utils.common.NumberUtils;
import com.yy.wga.mp.common.utils.common.StringUtils;
import com.yy.wga.mp.common.utils.date.DateUtils;
import com.yy.wga.mp.common.utils.http.HttpContextUtils;
import com.yy.wga.mp.common.utils.mapping.BeansUtils;
import com.yy.wga.mp.module.pay.client.AliPayClient;
import com.yy.wga.mp.module.pay.client.PayClient;
import com.yy.wga.mp.module.pay.client.WechatPayClient;
import com.yy.wga.mp.module.pay.client.enums.EPayOrderStatus;
import com.yy.wga.module.pay.client.request.alipay.*;
import com.yy.wga.module.pay.client.request.wechat.*;
import com.yy.wga.module.pay.client.response.alipay.*;
import com.yy.wga.module.pay.client.response.wechat.*;
import com.yy.wga.mp.module.pay.common.constant.RedisConstant;
import com.yy.wga.mp.module.pay.common.eunms.EPayChannel;
import com.yy.wga.mp.module.pay.common.eunms.EPayStatus;
import com.yy.wga.mp.module.pay.common.eunms.EPayType;
import com.yy.wga.mp.module.pay.entity.pojo.PayOrderDO;
import com.yy.wga.mp.module.pay.entity.pojo.PayTransferOrderDO;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author hongfeng
 * @date 2021/5/25
 * @desc
 */
@Slf4j
@Service
public class PayManager {
    /**
     * 微信支付回调地址
     */
    @Value(value = "${wechat.pay.notify.url:}")
    private String notifyUrl;
    /**
     * 微信日期格式化
     */
    private static final String WECHAT_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss+08:00";
    /**
     * 预订单有效时间 10分钟
     */
    private static final long EXPIRE_TIME = 1000 * 60 * 10;
    /**
     * 不同类型的打款client缓存
     */
    private final Map<Integer, PayClient> payClientCacheMap = new HashMap<>();

    private final PayOrderService payOrderService;
    private final PayTransferOrderService payTransferOrderService;
    private final RedissonClient redissonClient;

    public PayManager(Map<String, PayClient> payClientMap, PayOrderService payOrderService, PayTransferOrderService payTransferOrderService, RedissonClient redissonClient) {
        this.payOrderService = payOrderService;
        this.payTransferOrderService = payTransferOrderService;
        this.redissonClient = redissonClient;
        for (Map.Entry<String, PayClient> entry : payClientMap.entrySet()) {
            PayClient payClient = entry.getValue();
            payClientCacheMap.put(payClient.getType(), payClient);
        }
    }


    /**
     * https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_1.shtml
     * 商户系统先调用该接口在微信支付服务后台生成预支付交易单，返回正确的预支付交易会话标识后再按Native、JSAPI、APP等不同场景生成交易串调起支付。
     *
     * @param createPrePayOrderRequest 请求参数
     * @return 响应结果
     */
    public CreatePrePayOrderResponse createPreOrder(CreatePrePayOrderRequest createPrePayOrderRequest) {
        // 校验订单状态
        String orderRedisKey = RedisConstant.PAY_ORDER_KEY + createPrePayOrderRequest.getOutTradeNo();
        RLock lock = redissonClient.getLock(orderRedisKey);
        if (lock.tryLock()) {
            try {
                PayOrderDO payOrder = payOrderService.getOne(new LambdaQueryWrapper<PayOrderDO>()
                        .eq(PayOrderDO::getOrderNo, createPrePayOrderRequest.getOutTradeNo()));
                if (payOrder != null) {
                    throw new BusinessException("支付订单已存在，请重新支付");
                }
                CreatePrePayOrderResponse response = this.direct(createPrePayOrderRequest);
                payOrder = new PayOrderDO();
                payOrder.setAppKey(RequestUserHolder.getBaseRequest().getAppKey());
                payOrder.setAmount(createPrePayOrderRequest.getAmount());
                payOrder.setType(createPrePayOrderRequest.getType());
                payOrder.setPayType(createPrePayOrderRequest.getPayType());
                payOrder.setChannelType(createPrePayOrderRequest.getPayChannel());
                payOrder.setOrderNo(createPrePayOrderRequest.getOutTradeNo());
                payOrder.setStatus(EPayStatus.WAIT.getType());
                payOrder.setUserId(createPrePayOrderRequest.getUserId());
                payOrder.setErrorMsg("");
                payOrder.setAppId("");
                payOrder.setMchId("");
                payOrder.setPayOrderNo(response.getPayOrderNo());
                payOrderService.save(payOrder);
                return response;

            } finally {
                lock.unlock();
            }
        }
        return null;
    }

    /**
     * 直连支付
     * @param createPrePayOrderRequest 请求参数
     * @return 支付结果
     */
    private CreatePrePayOrderResponse direct(CreatePrePayOrderRequest createPrePayOrderRequest) {
        String payOrderNo = IdUtils.uuid();
        EPayChannel payChannel = EPayChannel.getByType(createPrePayOrderRequest.getPayChannel());
        if (payChannel == EPayChannel.WECHAT) {
            EPayType payType = EPayType.getByType(createPrePayOrderRequest.getPayType());
            if (payType == EPayType.APP) {
                WechatAppPreOrderRequest wechatAppPreOrderRequest = new WechatAppPreOrderRequest();
                wechatAppPreOrderRequest.setNotifyUrl(notifyUrl);
                wechatAppPreOrderRequest.setTimeExpire(DateUtils.dateFormat(new Date(System.currentTimeMillis() + EXPIRE_TIME), WECHAT_DATE_TIME_PATTERN));
                wechatAppPreOrderRequest.setOutTradeNo(payOrderNo);
                wechatAppPreOrderRequest.setAttach(createPrePayOrderRequest.getAttach());
                wechatAppPreOrderRequest.setDescription(createPrePayOrderRequest.getDescription());

                WechatAppPreOrderRequest.Amount amount = new WechatAppPreOrderRequest.Amount();
                amount.setTotal(createPrePayOrderRequest.getAmount().longValue());
                wechatAppPreOrderRequest.setAmount(amount);
                PayClient payClient = payClientCacheMap.get(payChannel.getType());
                if (payClient == null) {
                    throw new BusinessException("该渠道暂无法使用");
                }
                // 封装响应体
                WechatAppPreOrderResponse wechatAppPreOrderResponse = payClient.appPreOrder(wechatAppPreOrderRequest);
                CreatePrePayOrderResponse.AppWechatPayData wechatData = BeansUtils.map(wechatAppPreOrderResponse, CreatePrePayOrderResponse.AppWechatPayData.class);

                CreatePrePayOrderResponse response = new CreatePrePayOrderResponse();
                response.setAppWechatData(wechatData);
                response.setType(payChannel.getType());
                response.setPayOrderNo(payOrderNo);
                return response;
            } else if (payType.equals(EPayType.H5)) {
                WechatH5PreOrderRequest wechatH5PreOrderRequest = new WechatH5PreOrderRequest();
                wechatH5PreOrderRequest.setNotifyUrl(notifyUrl);
                wechatH5PreOrderRequest.setTimeExpire(DateUtils.dateFormat(new Date(System.currentTimeMillis() + EXPIRE_TIME), WECHAT_DATE_TIME_PATTERN));
                wechatH5PreOrderRequest.setOutTradeNo(payOrderNo);
                wechatH5PreOrderRequest.setAttach(createPrePayOrderRequest.getAttach());
                wechatH5PreOrderRequest.setDescription(createPrePayOrderRequest.getDescription());

                // 价格信息
                WechatH5PreOrderRequest.Amount amount = new WechatH5PreOrderRequest.Amount();
                amount.setTotal(createPrePayOrderRequest.getAmount().longValue());
                wechatH5PreOrderRequest.setAmount(amount);

                // h5支付信息
                WechatH5PreOrderRequest.SceneInfo sceneInfo = new WechatH5PreOrderRequest.SceneInfo();
                sceneInfo.setPayerClientIp(ServletUtil.getClientIP(HttpContextUtils.getHttpServletRequest()));
                WechatH5PreOrderRequest.SceneInfo.H5Info h5Info = new WechatH5PreOrderRequest.SceneInfo.H5Info();
                // 1:ANDROID 2:IOS 3:js
                String type;
                if (createPrePayOrderRequest.getSysType().equals(1)) {
                    type = "Android";
                } else if (createPrePayOrderRequest.getSysType().equals(2)) {
                    type = "iOS";
                } else {
                    type = "Wap";
                }
                h5Info.setType(type);
                sceneInfo.setH5Info(h5Info);
                wechatH5PreOrderRequest.setSceneInfo(sceneInfo);

                PayClient payClient = payClientCacheMap.get(payChannel.getType());
                if (payClient == null) {
                    throw new BusinessException("该渠道暂无法使用");
                }
                WechatH5PreOrderResponse wechatH5PreOrderResponse = payClient.h5PreOrder(wechatH5PreOrderRequest);

                // 封装响应体
                StringBuilder h5ReturnUrl = new StringBuilder(createPrePayOrderRequest.getH5ReturnUrl());
                if (h5ReturnUrl.length() > 0) {
                    h5ReturnUrl.append("?orderNo=").append(createPrePayOrderRequest.getOutTradeNo());
                    // 添加自定义参数
                    if (!CollectionUtils.isEmpty(createPrePayOrderRequest.getBusinessParams())) {
                        for (Map.Entry<String, String> entry : createPrePayOrderRequest.getBusinessParams().entrySet()) {
                            h5ReturnUrl.append("&").append(entry.getKey()).append("=").append(entry.getValue());
                        }
                    }
                    try {
                        h5ReturnUrl = new StringBuilder(URLEncoder.encode(h5ReturnUrl.toString(), "UTF-8"));
                    } catch (UnsupportedEncodingException e) {
                        log.error("url编码异常", e);
                        throw new BusinessException(EResponseCode.SYSTEM_BUSY_ERROR);
                    }
                }
                String h5Url = wechatH5PreOrderResponse.getH5Url() + "&redirect_url=" + h5ReturnUrl;
                wechatH5PreOrderResponse.setH5Url(h5Url);
                CreatePrePayOrderResponse.H5WechatPayData wechatData = BeansUtils.map(wechatH5PreOrderResponse, CreatePrePayOrderResponse.H5WechatPayData.class);
                CreatePrePayOrderResponse response = new CreatePrePayOrderResponse();
                response.setH5WechatData(wechatData);
                response.setPayOrderNo(payOrderNo);
                response.setType(payChannel.getType());
                return response;
            } else if (payType.equals(EPayType.JS)) {
                if (StringUtils.isBlank(createPrePayOrderRequest.getOpenId())) {
                    throw new BusinessException("openId不能为空");
                }
                WechatJsPreOrderRequest wechatJsPreOrderRequest = new WechatJsPreOrderRequest();
                wechatJsPreOrderRequest.setTimeExpire(DateUtils.dateFormat(new Date(System.currentTimeMillis() + EXPIRE_TIME), WECHAT_DATE_TIME_PATTERN));
                wechatJsPreOrderRequest.setOutTradeNo(payOrderNo);
                wechatJsPreOrderRequest.setAttach(createPrePayOrderRequest.getAttach());
                wechatJsPreOrderRequest.setDescription(createPrePayOrderRequest.getDescription());

                // 价格信息
                WechatJsPreOrderRequest.Amount amount = new WechatJsPreOrderRequest.Amount();
                amount.setTotal(createPrePayOrderRequest.getAmount().longValue());
                // todo 测试一分钱
//                amount.setTotal(1L);
                wechatJsPreOrderRequest.setAmount(amount);

                // 支付者
                WechatJsPreOrderRequest.Payer payer = new WechatJsPreOrderRequest.Payer();
                payer.setOpenid(createPrePayOrderRequest.getOpenId());
                wechatJsPreOrderRequest.setPayer(payer);

                PayClient payClient = payClientCacheMap.get(payChannel.getType());
                if (payClient == null) {
                    throw new BusinessException("该渠道暂无法使用");
                }
                WechatJsPreOrderResponse wechatJsPreOrderResponse = payClient.jsPreOrder(wechatJsPreOrderRequest);

                // 封装响应体
                CreatePrePayOrderResponse.JsWechatPayData wechatData = new CreatePrePayOrderResponse.JsWechatPayData();
                wechatData.setPrepayId(wechatJsPreOrderResponse.getPrepayId());
                wechatData.setNonceStr(wechatJsPreOrderResponse.getNonceStr());
                wechatData.setPaySign(wechatJsPreOrderResponse.getPaySign());
                wechatData.setSignType(wechatJsPreOrderResponse.getSignType());
                wechatData.setTimeStamp(wechatJsPreOrderResponse.getTimeStamp());
                CreatePrePayOrderResponse response = new CreatePrePayOrderResponse();
                response.setJsWechatPayData(wechatData);
                response.setType(payChannel.getType());
                response.setPayOrderNo(payOrderNo);
                return response;
            } else {
                throw new BusinessException("暂不支持其他支付类型");
            }
        } else if (payChannel == EPayChannel.ALIPAY) {
            EPayType payType = EPayType.getByType(createPrePayOrderRequest.getPayType());
            if (payType == EPayType.APP) {
                AliPayAppPreOrderRequest aliPayAppPreOrderRequest = new AliPayAppPreOrderRequest();
                aliPayAppPreOrderRequest.setTimeExpire(DateUtils.dateFormat(new Date(System.currentTimeMillis() + EXPIRE_TIME), WECHAT_DATE_TIME_PATTERN));
                aliPayAppPreOrderRequest.setOutTradeNo(payOrderNo);
                aliPayAppPreOrderRequest.setSubject(createPrePayOrderRequest.getSubject());
                aliPayAppPreOrderRequest.setBody(createPrePayOrderRequest.getDescription());
                aliPayAppPreOrderRequest.setTotalAmount(NumberUtils.changeF2Y(createPrePayOrderRequest.getAmount()));
                PayClient payClient = payClientCacheMap.get(payChannel.getType());
                if (payClient == null) {
                    throw new BusinessException("该渠道暂无法使用");
                }
                AliPayAppPreOrderResponse payPreOrderResponse = payClient.appPreOrder(aliPayAppPreOrderRequest);

                // 封装响应体
                CreatePrePayOrderResponse.AppAliPayData aliPayData = new CreatePrePayOrderResponse.AppAliPayData();
                aliPayData.setOrderInfo(payPreOrderResponse.getBody());
                CreatePrePayOrderResponse response = new CreatePrePayOrderResponse();
                response.setAppAliPayData(aliPayData);
                response.setType(payChannel.getType());
                response.setPayOrderNo(payOrderNo);
                return response;
            } else if (payType == EPayType.H5) {
                AliPayH5PreOrderRequest h5PreOrderRequest = new AliPayH5PreOrderRequest();
                h5PreOrderRequest.setTimeExpire(DateUtils.dateFormat(new Date(System.currentTimeMillis() + EXPIRE_TIME), WECHAT_DATE_TIME_PATTERN));
                h5PreOrderRequest.setOutTradeNo(payOrderNo);
                UrlQuery urlQuery = new UrlQuery(createPrePayOrderRequest.getBusinessParams());
                urlQuery.add("orderNo", createPrePayOrderRequest.getOutTradeNo());
                String returnUrl = createPrePayOrderRequest.getH5ReturnUrl() + "?" + urlQuery;
                h5PreOrderRequest.setReturnUrl(returnUrl);
                h5PreOrderRequest.setSubject(createPrePayOrderRequest.getSubject());
                h5PreOrderRequest.setBody(createPrePayOrderRequest.getDescription());
                h5PreOrderRequest.setTotalAmount(NumberUtils.changeF2Y(createPrePayOrderRequest.getAmount()));
                PayClient payClient = payClientCacheMap.get(payChannel.getType());
                if (payClient == null) {
                    throw new BusinessException("该渠道暂无法使用");
                }
                AliPayH5PreOrderResponse h5PreOrderResponse = payClient.h5PreOrder(h5PreOrderRequest);

                // 封装响应体
                CreatePrePayOrderResponse.H5AliPayData aliPayData = new CreatePrePayOrderResponse.H5AliPayData();
                aliPayData.setFrom(h5PreOrderResponse.getBody());
                CreatePrePayOrderResponse response = new CreatePrePayOrderResponse();
                response.setH5AliPayData(aliPayData);
                response.setType(payChannel.getType());
                response.setPayOrderNo(payOrderNo);
                return response;
            }
        }
        throw new BusinessException("支付方式错误");
    }

    /**
     * 查询用户信息
     * @param queryUserInfoRequest 查询用户信息请求参数
     * @return 用户信息
     */
    public QueryUserInfoResponse queryUserInfo(QueryUserInfoRequest queryUserInfoRequest) {
        if (StringUtils.isBlank(queryUserInfoRequest.getAuthToken()) && StringUtils.isBlank(queryUserInfoRequest.getChannelUserCode())) {
            throw new BusinessException("用户授权码和token必传一项");
        }
        // 没有token则使用授权码获取tokne
        if (StringUtils.isBlank(queryUserInfoRequest.getAuthToken())) {
            OauthTokenRequest oauthTokenRequest = new OauthTokenRequest();
            oauthTokenRequest.setCode(queryUserInfoRequest.getChannelUserCode());
            oauthTokenRequest.setChannelType(queryUserInfoRequest.getChannelType());
            oauthTokenRequest.setAppId(queryUserInfoRequest.getAppId());
            OauthTokenResponse oauthTokenResponse = this.oauthToken(oauthTokenRequest);
            queryUserInfoRequest.setAuthToken(oauthTokenResponse.getAccessToken());
        }
        // 获取用户信息
        PayClient payClient = payClientCacheMap.get(queryUserInfoRequest.getChannelType());
        if (payClient == null) {
            throw new BusinessException("该渠道暂无法使用");
        }
        // 获取用户信息
        AliPayQueryUserInfoRequest aliPayQueryUserInfoRequest = new AliPayQueryUserInfoRequest();
        aliPayQueryUserInfoRequest.setAuthToken(queryUserInfoRequest.getAuthToken());
        aliPayQueryUserInfoRequest.setAppId(queryUserInfoRequest.getAppId());
        AliPayQueryUserInfoResponse aliPayQueryUserInfoResponse = payClient.getUserInfo(aliPayQueryUserInfoRequest);

        // 返回
        QueryUserInfoResponse queryUserInfoResponse = new QueryUserInfoResponse();
        queryUserInfoResponse.setAppId(aliPayQueryUserInfoResponse.getAppId());
        queryUserInfoResponse.setAvatar(aliPayQueryUserInfoResponse.getAvatar());
        queryUserInfoResponse.setNickName(aliPayQueryUserInfoResponse.getNickName());
        queryUserInfoResponse.setChannelUserId(aliPayQueryUserInfoResponse.getAliPayUserId());
        return queryUserInfoResponse;
    }

    /**
     * 转账
     * @param transferRequest 转账用户信息
     * @return 转账结果
     */
    public TransferResponse transfer(TransferRequest transferRequest) {
        PayClient payClient = payClientCacheMap.get(transferRequest.getChannelType());
        if (payClient == null) {
            throw new BusinessException("该渠道暂无法使用");
        }
        // 初始化支付订单实体，这个不应该跟支付订单混在一起的，后面调整
        PayTransferOrderDO transferOrderDO = new PayTransferOrderDO();
        transferOrderDO.setAppKey(RequestUserHolder.getBaseRequest().getAppKey());
        transferOrderDO.setAccountType(transferRequest.getChannelType());
        transferOrderDO.setChannelUserId(transferRequest.getChannelUserId());
        transferOrderDO.setOrderNo(transferRequest.getOrderNo());
        transferOrderDO.setPayOrderNo(IdUtils.uuid());
        transferOrderDO.setBalance(Long.valueOf(transferRequest.getAmount()));
        transferOrderDO.setUserId(transferRequest.getUserId());
        transferOrderDO.setStatus(0);

        // 进行支付打款
        if (payClient instanceof AliPayClient) {
            AliPayTransferRequest aliPayTransferRequest = new AliPayTransferRequest();
            aliPayTransferRequest.setAppId(transferRequest.getAppId());
            aliPayTransferRequest.setAliPayUserId(transferRequest.getChannelUserId());
            aliPayTransferRequest.setAmount(new BigDecimal(NumberUtils.changeF2Y(transferRequest.getAmount())));
            aliPayTransferRequest.setIdentityType(transferRequest.getIdentityType());
            aliPayTransferRequest.setName(transferRequest.getName());
            aliPayTransferRequest.setOrderNo(transferOrderDO.getPayOrderNo());
            aliPayTransferRequest.setOrderTitle(transferRequest.getOrderTitle());
            aliPayTransferRequest.setRemark(transferRequest.getRemark());
            aliPayTransferRequest.setWithdrawAccount(transferRequest.getWithdrawAccount());
            AliPayTransferResponse aliPayTransferResponse = payClient.transfer(aliPayTransferRequest);

            if (aliPayTransferResponse.getStatus().equals(EPayOrderStatus.SUCCESS)) {
                transferOrderDO.setStatus(2);
                transferOrderDO.setFailReason("");
            } else {
                transferOrderDO.setStatus(3);
                transferOrderDO.setFailReason(aliPayTransferResponse.getErrorMsg());
            }
            // 保存转账订单
            transferOrderDO.setAppId(aliPayTransferResponse.getAppId());
            payTransferOrderService.save(transferOrderDO);

            // 返回支付结果
            TransferResponse response = new TransferResponse();
            response.setFinishTime(aliPayTransferResponse.getFinishTime());
            if (transferOrderDO.getStatus().equals(EPayStatus.FAIL.getType())) {
                response.setStatus(2);
                response.setFailReason(aliPayTransferResponse.getErrorMsg());
            } else {
                response.setStatus(1);
            }
            return response;
        } else if (payClient instanceof WechatPayClient) {
            WechatTransferRequest wechatTransferRequest = new WechatTransferRequest();
            wechatTransferRequest.setAmount(new BigDecimal(NumberUtils.changeF2Y(transferRequest.getAmount())));
            wechatTransferRequest.setOpenId(transferRequest.getOpenId());
            wechatTransferRequest.setName(transferRequest.getName());
            wechatTransferRequest.setOrderNo(transferOrderDO.getPayOrderNo());
            wechatTransferRequest.setTitle(transferRequest.getOrderTitle());
            wechatTransferRequest.setRemark(transferRequest.getRemark());
            WechatTransferResponse wechatTransferResponse = payClient.transfer(wechatTransferRequest);
            if (wechatTransferResponse.getStatus().equals(EPayOrderStatus.SUCCESS)) {
                transferOrderDO.setStatus(1);
                transferOrderDO.setFailReason("");
            } else {
                transferOrderDO.setStatus(3);
            }
            // 保存转账订单
            transferOrderDO.setAppId(wechatTransferResponse.getAppId());
            payTransferOrderService.save(transferOrderDO);

            // 返回支付结果
            TransferResponse response = new TransferResponse();
            if (transferOrderDO.getStatus().equals(EPayStatus.FAIL.getType())) {
                response.setStatus(2);
            } else {
                response.setStatus(0);
            }
            return response;
        } else {
            // todo 微信提现
        }
        throw new BusinessException(EResponseCode.SYSTEM_BUSY_ERROR);
    }

    /**
     * 获取授权码 -- 支付宝
     * @param oauthTokenRequest 请求参数
     * @return 授权码信息
     */
    public OauthTokenResponse oauthToken(OauthTokenRequest oauthTokenRequest) {
        PayClient payClient = payClientCacheMap.get(oauthTokenRequest.getChannelType());
        if (payClient == null) {
            throw new BusinessException("该渠道暂无法使用");
        }
        // 获取授权码
        if (payClient instanceof AliPayClient) {
            AliPayOauthTokenRequest aliPayOauthTokenRequest = new AliPayOauthTokenRequest();
            aliPayOauthTokenRequest.setCode(oauthTokenRequest.getCode());
            aliPayOauthTokenRequest.setGrantType(1);
            aliPayOauthTokenRequest.setAppId(oauthTokenRequest.getAppId());
            AliPayOauthTokenResponse aliPayOauthTokenResponse = payClient.oauthToken(aliPayOauthTokenRequest);

            return BeansUtils.map(aliPayOauthTokenResponse, OauthTokenResponse.class);
        }
        throw new BusinessException(EResponseCode.SYSTEM_BUSY_ERROR);
    }

    /**
     * 退款
     * @param orderNo 订单号
     * @return 支付状态 1、待支付 2、支付成功 3、支付失败 4、转入退款 5、交易取消
     */
    public Integer refund(String orderNo) {
        PayOrderDO payOrderDO = payOrderService.getOne(new LambdaQueryWrapper<PayOrderDO>()
                .eq(PayOrderDO::getOrderNo, orderNo));
        if (payOrderDO == null) {
            throw new BusinessException("未查询到支付订单");
        }
        payOrderService.update(new LambdaUpdateWrapper<PayOrderDO>()
                .eq(PayOrderDO::getId, payOrderDO.getId())
                .set(PayOrderDO::getStatus, 4));
        Integer payOrderStatus = this.directRefund(payOrderDO);
        if (payOrderStatus != 4) {
            payOrderService.update(new LambdaUpdateWrapper<PayOrderDO>()
                    .eq(PayOrderDO::getId, payOrderDO.getId())
                    .set(PayOrderDO::getStatus, payOrderStatus));
        }
        return payOrderStatus;
    }

    /**
     * 直连退款
     * @return 订单状态
     */
    public Integer directRefund(PayOrderDO payOrderDO) {
        // 1、待支付 2、支付成功 3、支付失败 4、转入退款 5、交易取消 6、退款中
        int payOrderStatus = EPayOrderStatus.CANCEL.getType();

        Integer channelType = payOrderDO.getChannelType();
        PayClient payClient = payClientCacheMap.get(channelType);
        if (channelType.equals(EPayChannel.ALIPAY.getType())) {
            AliPayRefundRequest refundRequest = new AliPayRefundRequest();
            refundRequest.setAppId(payOrderDO.getAppId());
            refundRequest.setOutTradeNo(payOrderDO.getPayOrderNo());
            refundRequest.setRefundAmount(NumberUtils.changeF2Y(payOrderDO.getAmount()));
            payClient.refund(refundRequest);
        } else if (channelType.equals(EPayChannel.WECHAT.getType())) {
            WechatRefundRequest wechatRefundRequest = new WechatRefundRequest();
            wechatRefundRequest.setOutTradeNo(payOrderDO.getPayOrderNo());
            wechatRefundRequest.setOutRefundNo(IdUtils.uuid());
            WechatRefundRequest.Amount amount = new WechatRefundRequest.Amount();
            // 测试写死1分钱
//            amount.setRefund(1L);
//            amount.setTotal(1L);
            amount.setRefund(payOrderDO.getAmount().longValue());
            amount.setTotal(payOrderDO.getAmount().longValue());
            amount.setCurrency("CNY");
            wechatRefundRequest.setAmount(amount);
            WechatRefundResponse refundResponse = payClient.refund(wechatRefundRequest);
            switch (refundResponse.getStatus()) {
                case "CLOSED":
                    throw new BusinessException("微信退款关闭，无法退款");
                case "PROCESSING":
                    log.info("微信退款返回退款处理中状态");
                    payOrderStatus = 4;
                    break;
                case "ABNORMAL":
                    throw new BusinessException("微信退款返回退款异常状态");
            }
        } else {
            throw new BusinessException("支付订单订单有误");
        }
        return payOrderStatus;
    }
}
